﻿/// <reference path="./node_modules/@types/jquery/index.d.ts"  />
/// <reference path="./node_modules/@popperjs/core/index.d.ts" />
/// <reference path="./node_modules/@types/bootstrap/index.d.ts" />


if (!window) {
    throw "无法访问DOM对象。";
}
if (typeof jQuery === "undefined" && typeof $ === "undefined") {
    throw "缺少JQuery组件。(sharp.js需要在jquery之后载入)";
}
if (!(typeof bootstrap.Modal === 'function')) {
    throw "缺少bootStrap组件。";
}


document.onreadystatechange = function (e: Event): any {
    if (document.readyState === "interactive") {
        console.log("页面DOM已解析，可进行交互。");
    }
    else if (document.readyState === "complete") {
        console.log("页面资源已加载完成。");
    }
};



type ProgressEventHandler = (loaded: number, total: number) => void;
interface WebApiResult {
    done(callback: (WebApiResult) => void): WebApiResult;
    fail(callback: (WebApiResult) => void): WebApiResult;
    always(callback: (WebApiResult) => void): WebApiResult;
}
interface JQuery {
    postForm(upProgress?: (loaded: number, total: number) => void,
        downProgress?: (loaded: number, total: number) => void): WebApiResult;
    resetForm();

    mask(content: string, maskDivClass?: string): JQuery<HTMLElement>;
    unMask();
    busy(msg?: string);
    unBusy();
}
interface Window {
    isType(obj: any, typeName: string): boolean;
    formDataToJson(formData: FormData): object;
    apiPostText(url: string, data?: string): WebApiResult;
    apiPostJson(url: string, data?: object): WebApiResult;
    apiPostForm(url: string, data?: object | FormData, upProgress?: ProgressEventHandler, downProgress?: ProgressEventHandler): WebApiResult;
    apiGet(url: string, paras?: object, downProgress?: ProgressEventHandler): WebApiResult;
    httpGet(url: string, paras?: object, downProgress?: ProgressEventHandler): JQuery.jqXHR

    dlgSuccess(title: string, content: string, onHideHandler?: Function): JQuery<HTMLElement>;
    dlgError(title: string, content: string, onHideHandler?: Function): JQuery<HTMLElement>;
    dlg(title: string, content: string, btns: ["ok"] | ["ok", "cancel"] | ["yes", "no"], btnclickcallback: (btn: string, dialog: any, e: Event) => boolean): JQuery<HTMLElement>;
    input(title: string, defValue: any, onresult: (res: string) => void): JQuery<HTMLElement>;

    toast(title1: string, title2: string, content: string, delay?: number, closeCallback?: Function): bootstrap.Toast

    findParent(ele: HTMLElement, selector: string, endele?: HTMLElement): HTMLElement;
}
interface String {
    format(...args: string[]): string;
    format(arg: object): string;
    Format(...args: string[]): string;
    Format(arg: object): string;
    startWith(arg: string): boolean;
    endWith(arg: string): boolean;
}
interface Date {
    Format(fmt: string): string;
    format(fmt: string): string;
}



//#region 扩展字符串
String.prototype["startWith"] = function (str) {
    var reg = new RegExp("^" + str);
    return reg.test(this);
};

String.prototype["endWith"] = function (str) {
    var reg = new RegExp(str + "$");
    return reg.test(this);
};

String.prototype["Format"] = String.prototype["format"] = function (args) {
    var result = this;
    if (arguments.length > 0) {
        if (arguments.length === 1 && typeof args === "object") {
            for (var key in args) {
                if (args[key] !== undefined) {
                    var regexp = new RegExp("({" + key + "})", "g");
                    var value = args[key];
                    if (value === null) {
                        value = "";
                    }
                    result = result.replace(regexp, value);
                }
            }
        }
        else {
            for (var i = 0; i < arguments.length; i++) {
                if (arguments[i] !== undefined) {
                    var reg_exp = new RegExp("({[" + i + "]})", "g");

                    result = result.replace(reg_exp, arguments[i]);
                }
            }
        }
    }
    return result;
};

//#endregion

//#region 扩展日期格式


// 对Date的扩展，将 Date 转化为指定格式的String 
// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符， 
// 年(y)可以用 1-4 个占位符，毫秒(S)只能用 1 个占位符(是 1-3 位的数字) 
// 例子： 
// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 
// (new Date()).Format("yyyy-M-d h:m:s.S")      ==> 2006-7-2 8:9:4.18 
Date.prototype["Format"] = Date.prototype["Format"] = function (fmt) { //author: meizz 
    var o = {
        "M+": this.getMonth() + 1,                 //月份 
        "d+": this.getDate(),                    //日 
        "h+": this.getHours(),                   //小时 
        "m+": this.getMinutes(),                 //分 
        "s+": this.getSeconds(),                 //秒 
        "q+": Math.floor((this.getMonth() + 3) / 3), //季度 
        "S": this.getMilliseconds()             //毫秒 
    };
    if (/(y+)/.test(fmt))
        fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o)
        if (new RegExp("(" + k + ")").test(fmt))
            fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    return fmt;
};
//#endregion


/**
 * webapi的反馈结果
 * */
class WebApiResult {

    constructor(jqxhr: JQuery.jqXHR) {
        var me: WebApiResult = this;
        jqxhr.done(function (result) {
            me.status = result.status;
            me.message = result.message;
            me.data = result.data;
            if (result.status === 1) {
                me.call_done(me);
            }
            else {
                me.call_fail(me);
            }
        });
        jqxhr.fail(function (xhr) {
            //异常状态也转为apiresult
            me.status = -xhr.status;
            me.message = xhr.responseText;
            if (!me.message) {
                if (me.status == 0) {
                    me.message = "网络异常。";
                }
                else if (me.status == -404) {
                    me.message = "请求的目标不存在。";
                }
            }

            me.data = null;
            me.call_fail(me);
        });
        jqxhr.always(function () {
            me.call_always(me);
        });
    }
    public status: number;
    public message: string;
    public data: any;

    private _done: Array<(WebApiResult) => void>;
    private _fail: Array<(WebApiResult) => void>;
    private _always: Array<(WebApiResult) => void>;

    public call_done(result: WebApiResult): WebApiResult {
        if (this._done) {
            try {
                this._done.forEach(element => {
                    element(result);
                });

            } catch (error) {

            }

        }
        return this;
    }
    public call_fail(result: WebApiResult): WebApiResult {

        if (this._fail) {
            try {
                this._fail.forEach(element => {
                    element(result);
                });
            } catch (error) {

            }

        }
        return this;
    }
    public call_always(result: WebApiResult): WebApiResult {
        if (this._always) {
            try {
                this._always.forEach(element => {
                    element(result);
                });
            } catch (error) {

            }

        }
        return this;
    }

    public done(callback: (WebApiResult) => void): WebApiResult {
        if (!this._done) {
            this._done = new Array<(WebApiResult) => void>();
        }
        this._done.push(callback);
        return this;
    }
    public fail(callback: (WebApiResult) => void): WebApiResult {
        if (!this._fail) {
            this._fail = new Array<(WebApiResult) => void>();
        }
        this._fail.push(callback);
        return this;
    }
    public always(callback: (WebApiResult) => void): WebApiResult {
        if (!this._always) {
            this._always = new Array<(WebApiResult) => void>();
        }
        this._always.push(callback);
        return this;
    }
}


/**
 * Html编码工具
 * */
class HtmlUtil {
    /**
     * 转为HTML编码
     * @param {string} str HTML字符串
     * @returns {string} 返回编码后的字符串
     */
    static htmlEncode(str: string): string {
        var s = "";
        if (!str || str.length === 0) return "";
        s = str.replace(/&/g, "&amp;");
        s = s.replace(/</g, "&lt;");
        s = s.replace(/>/g, "&gt;");
        s = s.replace(/ /g, "&nbsp;");
        s = s.replace(/\'/g, "&#39;");
        s = s.replace(/\"/g, "&quot;");
        return s;
    }
    /**
     * HTML解码
     * @param {string} str html编码字符串
     * @returns {string} 返回解码的HTML字符串
     */
    static htmlDecode(str: string): string {
        var s = "";
        if (!str || str.length === 0) return "";
        s = str.replace(/&amp;/g, "&");
        s = s.replace(/&lt;/g, "<");
        s = s.replace(/&gt;/g, ">");
        s = s.replace(/&nbsp;/g, " ");
        s = s.replace(/&#39;/g, "\'");
        s = s.replace(/&quot;/g, "\"");
        return s;
    }
}

class Guid {

    private static gen(count = 1) {
        let out = '';
        for (let i = 0; i < count; i++) out += ((1 + Math.random()) * 0x10000 | 0).toString(16).substring(1);
        return out;
    }

    private static readonly globals = {
        guidDefaultValue: '00000000-0000-0000-0000-000000000000',
        validationPattern: '^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$'
    };

    private value: string;

    protected constructor(guid: string) {
        if (!guid) throw new TypeError('Invalid argument; `value` has no value.');
        this.value = Guid.globals.guidDefaultValue;
        if (guid && Guid.isGuid(guid)) this.value = guid;
    }

    static validator = new RegExp(this.globals.validationPattern, 'i');

    static isGuid = (guid: Guid | string): boolean => guid && (guid instanceof Guid || Guid.validator.test(guid.toString()));

    static create = (): Guid => new Guid([Guid.gen(2), Guid.gen(), Guid.gen(), Guid.gen(), Guid.gen(3)].join('-'));

    static NewGuid(): Guid {
        return Guid.create();
    }

    static createEmpty = (): Guid => new Guid(Guid.globals.guidDefaultValue);

    static parse = (guid: string): Guid => new Guid(guid);

    static raw = (): string => [Guid.gen(2), Guid.gen(), Guid.gen(), Guid.gen(), Guid.gen(3)].join('-');

    static EMPTY = Guid.parse(Guid.globals.guidDefaultValue);

    /*
     * Comparing string `value` against provided `guid` will auto-call
     * toString on `guid` for comparison
     */
    equals = (other: Guid): boolean => Guid.isGuid(other) && this.value.toUpperCase() === other.toString().toUpperCase();

    isEmpty = (): boolean => this.value === Guid.globals.guidDefaultValue;

    toString = (): string => this.value;

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    toJSON(): any { return { value: this.value }; }
}


class WindowHelper {
    /**
     * 判断对象是否为指定的类型
     * @param {any} obj 要判断类型的实体
     * @param {string} typeString 类型名称
     * @returns {boolean} 返回true|false
     */
    static isType(obj: any, typeName: string): boolean {
        return Object.prototype.toString.call(obj) === '[object ' + typeName + ']';
    }

    /**
     * 将FormData对象转换为JSON对象
     * @param {FormData} formData FormData对象
     * @returns {Object} 返回JSON对象
     */
    static formDataToJson(formData: FormData): object {
        var objData = {};
        formData.forEach((v, k, f) => {
            objData[k] = v;
        });
        return objData;
    };
    /**
     * 查找父元素
     * @param ele 当前元素
     * @param selector 用于匹配元素的选择器
     * @param endele 终止查找的元素
     */
    static findParent(ele: HTMLElement, selector: string, endele?: HTMLElement): HTMLElement {
        var jq = $(ele);

        if (jq.is(selector)) {
            return ele;
        }
        var ps = $(ele).parents();
        for (var i in ps) {
            var p = ps[i];
            if ($(p).is(selector)) {
                return p;
            }
            if (p === endele) {
                return null;
            }
        }
        return null;
    }
}

class API {
    /**
        * 将json对象提交到webapi
        * @param {string} url 要提交到的url
        * @param {object} data 要提交的json数据
        * @returns {WebApiResult} 返回jqXHR
        */
    static apiPostJson(url: string, data: object): WebApiResult {
        var jqxhr = $.ajax({
            url: url,
            async: true,
            method: 'POST',
            data: JSON.stringify(data),
            dataType: "json",//"xml", "html", "script", "json", "jsonp", "text" 
            contentType: "application/json;charset=UTF-8",
            processData: false,
            cache: false,
            success: function (data) {
            },
            error: function (jqXHR) {
                console.log(JSON.stringify(jqXHR));
            }

        });
        return new WebApiResult(jqxhr);
    };
    /**
     * 将文本提交到http正文
     * @param url
     * @param data
     */
    static apiPostText(url: string, data: string): WebApiResult {
        var jqxhr = $.ajax({
            url: url,
            async: true,
            method: 'POST',
            data: JSON.stringify(data),
            dataType: "text",//"xml", "html", "script", "json", "jsonp", "text" 
            contentType: "text/plain;charset=UTF-8",
            processData: false,
            cache: false,
            success: function (data) {
            },
            error: function (jqXHR) {
                console.log(JSON.stringify(jqXHR));
            }

        });
        return new WebApiResult(jqxhr);
    }

    /**
   * 将表单数据提交到webapi
   * @param {string} url 要提交到的url
   * @param {object|FormData} data 要提交的json|FormData数据
   * @param {ProgressEventHandler} upProgress 上传数据进度处理
   * @param {ProgressEventHandler} downProgress 下载数据进度处理 
   * @returns {WebApiResult} 返回WebApiResult
   */
    static apiPostForm(url: string, data: object | FormData, upProgress?: ProgressEventHandler, downProgress?: ProgressEventHandler): WebApiResult {
        if (!WindowHelper.isType(data, "FormData")) {
            var fd = new FormData();
            for (var k in data) {
                fd.append(k, data[k]);
            }
            data = fd;
        }
        var jqxhr = $.ajax({
            url: url,
            async: true,
            method: 'POST',
            data: data,
            dataType: "json",//"xml", "html", "script", "json", "jsonp", "text"
            contentType: false, // 注意这里应设为false
            processData: false,
            cache: false,
            //complete: function (XHR, TS) {
            //    if (complete) {
            //        complete(XHR, TS);
            //    }

            //},
            xhr: function () {
                var xhr = $.ajaxSettings.xhr();
                xhr.upload.onprogress = function (evt) {
                    if (evt.lengthComputable) {
                        var percentComplete = evt.loaded / evt.total;
                        if (upProgress) {
                            upProgress(evt.loaded, evt.total);
                        }
                    }
                };
                xhr.onprogress = function (evt) {
                    if (evt.lengthComputable) {
                        var percentComplete = evt.loaded / evt.total;
                        if (downProgress) {
                            downProgress(evt.loaded, evt.total);
                        }
                    }
                };
                return xhr;
            }
        });

        return new WebApiResult(jqxhr);
    }


    /**
    * 从webapi获取数据
    * @param {string} url 要请求的url
    * @param {object} paras 请求的参数
    * @param {ProgressEventHandler} downProgress 下载进度
    * @returns {WebApiResult} 返回jqXHR对象
    */
    static apiGet(url: string, paras?: object, downProgress?: ProgressEventHandler): WebApiResult {

        var jqxhr = $.ajax({
            url: url,
            contentType: "application/x-www-form-urlencoded;charset=utf-8",
            type: 'GET',
            async: true,
            data: paras,
            dataType: 'json',
            cache: false,
            xhr: function () {
                var xhr = $.ajaxSettings.xhr();
                //Download progress
                xhr.onprogress = function (evt) {
                    if (evt.lengthComputable) {
                        var percentComplete = evt.loaded / evt.total;
                        if (downProgress) {
                            downProgress(evt.loaded, evt.total);
                        }
                    }
                };
                return xhr;
            }
        });
        return new WebApiResult(jqxhr);
    }


    static httpGet(url: string, paras?: object, downProgress?: ProgressEventHandler): JQuery.jqXHR {

        return $.ajax({
            url: url,
            contentType: "application/x-www-form-urlencoded;charset=utf-8",
            type: 'GET',
            async: true,
            data: paras,
            dataType: 'text',
            cache: false,
            xhr: function () {
                var xhr = $.ajaxSettings.xhr();
                //Download progress
                xhr.onprogress = function (evt) {
                    if (evt.lengthComputable) {
                        var percentComplete = evt.loaded / evt.total;
                        if (downProgress) {
                            downProgress(evt.loaded, evt.total);
                        }
                    }
                };
                return xhr;
            }
        });
    }
}

class Dialog {
    static dlgSuccess(content: string, title: string, onHideHandler: (event: JQueryEventObject) => void): JQuery<HTMLElement> {
        if (!title) {
            title = "";
        }
        if (!content) {
            content = "";
        }
        var str = '<div class="modal fade" tabindex="-1" data-bs-backdrop="static" role="dialog" aria-hidden="true">' +
            '<div class="modal-dialog modal-dialog-centered" role="document">' +
            '<div class="modal-content">' +
            '<div class="modal-header">' +
            '<h5 class="modal-title" style="color:green"><i class="fa fa-check-circle"></i>' + title + '</h5>' +
            '<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">' +
            '</button>' +
            '</div>' +
            '<div class="modal-body alert-success">' + content +
            '</div>' +
            '<div class="modal-footer">' +
            '<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>' +
            '</div>' +
            '</div>' +
            '</div>' +
            '</div>';

        var dlg = $(str);
        dlg.on("hidden.bs.modal", onHideHandler);
        dlg.modal("show");
        return dlg;
    };
    static dlgInfo(content: string, title: string, onHideHandler: (event: JQueryEventObject) => void): JQuery<HTMLElement> {
        if (!title) {
            title = "";
        }
        if (!content) {
            content = "";
        }
        var str = '<div class="modal fade" tabindex="-1" data-bs-backdrop="static" role="dialog" aria-hidden="true">' +
            '<div class="modal-dialog modal-dialog-centered" role="document">' +
            '<div class="modal-content">' +
            '<div class="modal-header">' +
            '<h5 class="modal-title"><i class="fa fa-check-circle"></i>' + title + '</h5>' +
            '<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">' +
            '</button>' +
            '</div>' +
            '<div class="modal-body alert-info">' + content +
            '</div>' +
            '<div class="modal-footer">' +
            '<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>' +
            '</div>' +
            '</div>' +
            '</div>' +
            '</div>';

        var dlg = $(str);
        dlg.on("hidden.bs.modal", onHideHandler);
        dlg.modal("show");
        return dlg;
    };

    static dlgError(content: string, title: string, onHideHandler: (event: JQueryEventObject) => void): JQuery<HTMLElement> {
        if (!title) {
            title = "";
        }
        if (!content) {
            content = "";
        }
        var str = '<div class="modal fade" tabindex="-1" data-bs-backdrop="static" role="dialog" aria-hidden="true">' +
            '<div class="modal-dialog modal-dialog-centered" role="document">' +
            '<div class="modal-content">' +
            '<div class="modal-header">' +
            '<h5 class="modal-title"><i class="fa fa-exclamation-circle"></i>' + title + '</h5>' +
            '<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">' +
            '</button>' +
            '</div>' +
            '<div class="modal-body alert-danger">' + content +
            '</div>' +
            '<div class="modal-footer">' +
            '<button type="button" class="btn btn-danger" data-bs-dismiss="modal">关闭</button>' +
            '</div>' +
            '</div>' +
            '</div>' +
            '</div>';
        var dlg = $(str);
        dlg.on("hidden.bs.modal", onHideHandler);
        dlg.modal("show");
        return dlg;
    };

    /**
     * 弹出对话框
     * @param {string} title 对话框标题
     * @param {string} content 对话框内容
     * @param {Array<string>} btns 支持的按钮
     * @param {(btn: string, dialog: any, e: Event) => boolean} btnclickcallback 按钮回调
     * @returns {JQuery} 返回对话框的JQuery对象
     */
    static dlg(title: string, content: string, btns: ["ok"] | ["ok", "cancel"] | ["yes", "no"], btnclickcallback: (btn: string, dialog: any, e: Event) => boolean): JQuery<HTMLElement> {
        var btnstr = "";
        var withclose = false;
        if (!btns) {
            btns = ["ok"];
        }
        if ($.inArray('ok', btns) >= 0) {
            btnstr += '<button type="button" class="btn btn-primary" data-btntype="ok">确认</button>';
        }
        if ($.inArray('cancel', btns) >= 0) {
            btnstr += '<button type="button" class="btn btn-default" data-bs-dismiss="modal" data-btntype="cancel">取消</button>';
        }
        if ($.inArray('yes', btns) >= 0) {
            btnstr += '<button type="button" class="btn btn-primary" data-btntype="yes">是</button>';
        }
        if ($.inArray('no', btns) >= 0) {
            btnstr += '<button type="button" class="btn btn-default" data-bs-dismiss="modal" data-btntype="no">否</button>';
        }
        if ($.inArray('close', btns) >= 0) {
            withclose = true;
        }
        var gid = Guid.NewGuid().toString();
        var template = ('<div class="modal fade" data-bs-backdrop="static" id="' + gid + '" tabindex="-1" role="dialog">'
            + '<div class="modal-dialog modal-dialog-centered" role="document">'
            + '<div class="modal-content">'
            + '<div class="modal-header">'
            + '<h4 class="modal-title">{0}</h4>'
            + (withclose ? '<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close" data-btntype="close"><span aria-hidden="true">&times;</span></button>' : '')
            + '</div>'
            + '<div class="modal-body">'
            + '{1}'
            + '</div>'
            + '<div class="modal-footer">'
            + '{2}'
            + '</div>'
            + '</div>'
            + '</div>'
            + '</div>').format(title, content, btnstr);
        var dialog = $(template);

        dialog.find("button[data-btntype]").on("click", function (event: Event) {
            if (btnclickcallback) {
                var res = btnclickcallback($(this).data("btntype"), dialog, event);
                if (!res) {//返回false则隐藏对话框，返回true则保持对话框
                    dialog.modal("hide");
                }
            }

        });
        dialog.on("hidden.bs.modal", function () {

            dialog.modal("dispose");
            dialog.remove();//动态对话框隐藏后移除该动态生成的元素
        });
        dialog.modal("show");
        return dialog;
    };

    /**
     * 弹出用户输入对话框
     * @param {string} title 标题
     * @param {string} defValue 默认值
     * @param {(res:string)=>void} onresult 输入结果回调
     */
    static input(title: string, defValue: string, onresult: (res: string) => void): JQuery<HTMLElement> {
        //var val = prompt(title, defValue);
        //if (onresult) {
        //    onresult(val);
        //}
        var gid = Guid.NewGuid().toString();
        var tid = `input_${gid}`;
        return Dialog.dlg(title, `<input type="text" id="${tid}" class="form-control" value="${HtmlUtil.htmlEncode(defValue)}"/>`, ["ok", "cancel"], (btn, dialog, e) => {
            if (btn == "ok") {
                onresult(<string>$("#" + tid).val());
            }
            return false;
        });
    };

    static toast(title1: string, title2: string, content: string, delay?: number, closeCallback?: Function): bootstrap.Toast {

        var container = $("body>.toast-container.position-fixed");
        if (container.length == 0) {
            container = $(`<div class="toast-container position-fixed top-0 start-50 translate-middle-x" style="left:0;top:0;bottom:0;right:0;z-index:20;"></div>`);
            $("body").append(container);
        }

        var dom = `<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
    <div class="toast-header"> 
        <strong class="me-auto">${title1}</strong>
        <small class="text-muted">${title2}</small>
        <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
    </div>
    <div class="toast-body">
${content}
    </div>
</div>`;
        var node = $(dom);
        container.append(node);
        if (delay) {
            node.data("bs-delay", delay);
        }

        var t = bootstrap.Toast.getOrCreateInstance(node[0]);
        t.show();
        node[0].addEventListener('hidden.bs.toast', function () {
            t.dispose();
            node.remove();
            if (container.find(">*").length == 0) {
                container.remove();
            }
            if (closeCallback) {
                closeCallback();
            }
        })
        return t;
    };

}

//#region 扩展window对象
Window.prototype["findParent"] = WindowHelper.findParent;
Window.prototype["isType"] = WindowHelper.isType;
Window.prototype["formDataToJson"] = WindowHelper.formDataToJson;
Window.prototype["apiPostText"] = API.apiPostText;
Window.prototype["apiPostJson"] = API.apiPostJson;
Window.prototype["apiPostForm"] = API.apiPostForm;
Window.prototype["apiGet"] = API.apiGet;
Window.prototype["httpGet"] = API.httpGet;

Window.prototype["dlgSuccess"] = Dialog.dlgSuccess;
Window.prototype["dlgError"] = Dialog.dlgError;
Window.prototype["dlg"] = Dialog.dlg;
Window.prototype["input"] = Dialog.input;
Window.prototype["toast"] = Dialog.toast;

//#endregion


(function () {
    $.extend($.fn, {
        /*
         *显示遮罩层
         */
        mask: function (content: string, maskDivClass: string): JQuery<HTMLElement> {
            this.unMask();
            // 参数
            var op = {
                opacity: 0.6,
                z: 19,
                bgcolor: 'rgba(0,0,0,0.5)'
            };
            var original = $(this); // $(document.body);
            original.css("position", "relative");

            var position = { top: 0, left: 0 };

            // 创建一个 Mask 层，追加到对象中
            var maskDiv = $('<div class="maskdivgen" style="display:flex;justify-content: center;align-items: center;cursor:wait;"></div>');
            maskDiv.appendTo(original);
            //var maskWidth = original.outerWidth();
            //if (!maskWidth) {
            //    maskWidth = original.width();
            //}
            //var maskHeight = original.outerHeight();
            //if (!maskHeight) {
            //    maskHeight = original.height();
            //}
            maskDiv.css({
                position: 'absolute',
                top: position.top,
                left: position.left,
                'z-index': op.z,
                width: "100%",// maskWidth,
                height: "100%",// maskHeight,
                'background-color': op.bgcolor,
                opacity: 0
            });
            if (maskDivClass) {
                maskDiv.addClass(maskDivClass);
            }
            if (content) {
                var msgDiv = $(`<div>${content}</div>`);
                msgDiv.appendTo(maskDiv);
                var widthspace = maskDiv.width() - msgDiv.width();
                var heightspace = maskDiv.height() - msgDiv.height();
                msgDiv.css({
                    top: heightspace / 2 - 2,
                    left: widthspace / 2 - 2
                });
            }
            maskDiv.fadeIn('fast', function () {
                // 淡入淡出效果
                $(this).fadeTo('slow', op.opacity);
            });
            return maskDiv;
        },
        /*
         *去除遮罩层
         */
        unMask: function () {
            var original = $(document.body);
            if (this[0] && this[0] !== window.document) {
                original = $(this[0]);
            }
            original.find("> div.maskdivgen").fadeOut('slow', function () {
                $(this).remove();
            });
        },
        /**
         * 显示加载遮罩层
         * */
        busy: function (msg?: string) {
            var tag = $(this);
            //var id = '___busymask_style';
            //if ($("head>#" + id).length == 0) {
            //    //动态插入动画样式
            //    var style = document.createElement('style');
            //    style.type = 'text/css';
            //    style.id = id;
            //    style.innerHTML = '@keyframes busymaskrotate{ 0% {transform:rotateZ(0deg);} 100% {transform:rotateZ(360deg);}} @-webkit-keyframes busymaskrotate{ 0% {transform:rotateZ(0deg);} 100% {transform:rotateZ(360deg);}} .my-spin::before{animation:busymaskrotate 2s infinite linear;}';
            //    document.getElementsByTagName('head').item(0).appendChild(style);
            //}

            //tag.mask("<i class=\"bi bi-arrow-repeat my-spin\" style=\"font-size:1.5rem;color:white;\"></i>");
            tag.mask(`<div class="spinner-border text-primary" style="display:block;margin:auto;" role="status">
<span class="visually-hidden">Loading...</span></div>
<div style="color:white;">${msg ? msg : ""}</div>`);
        },
        /**
         * 隐藏加载遮罩层
         * */
        unBusy: function () {
            var tag = $(this);
            tag.unMask();
        }
    });
})();


/*JQuery Extension*/
(
    /**
     * 
     * @param {JQuery<HTMLFormElement>} jq JQuery<HTMLFormElement>对象
     */
    function (jq) {
        jq.fn.extend({
            /**
             * 异步提交form的数据到API
             * @param {Function<number,number>} upProgress 上传进度
            * @param {Function<number, number>} downProgress 下载进度
            * @returns {JQuery.jqXHR} 返回jqXHR对象
             */
            apiPostForm: function (upProgress?: (loaded: number, total: number) => void,
                downProgress?: (loaded: number, total: number) => void): WebApiResult {
                var form = $(this);

                var url = form.attr("action");
                var formData = new FormData(form[0]);
                return API.apiPostForm(url, formData, upProgress, downProgress);

            },
            /**
             * 重置表单
             * */
            resetForm: function () {
                var form = $(this);
                form[0].reset();

            },
            /**
             * 将对象中的值置入表单
             * @param {any} data json对象
             */
            setForm: function (data) {
                var form = <JQuery<HTMLElement>>$(this);
                if (!data) {
                    form.resetForm();
                    return;
                } else {
                    for (var i in data) {
                        var tag = form.find("[name='" + i + "']");
                        if (tag.length > 0) {
                            var tagname = tag[0].tagName.toLowerCase();
                            if (tagname === "input") {
                                if (tag.attr("type") === "radio") {
                                    form.find("[name='" + i + "'][value='" + data[i] + "']").attr("checked", "checked");
                                }
                                else if (tag.attr("type") === "checkbox") {
                                    form.find("[name='" + i + "'][value='true']").attr("checked", data[i]);
                                }
                                else {
                                    tag.val(data[i]);
                                }
                            }
                            else if (tagname === "select") {
                                tag.find("option[value='" + data[i] + "']").attr("selected", "selected");
                            }
                            else {
                                tag.text(data[i]);
                            }
                        }
                    }
                }
            },
            /**
             * 以JSON的形式获取表单填写的数据
             * 
             * */
            getFormDataAsJson: function () {
                var form = $(this);
                var formData = new FormData(form[0]);
                return WindowHelper.formDataToJson(formData);
            },
            /**
             * 自定义form的提交时的ajax操作并阻止form使用浏览器内置提交功能，调用此方法后表单不会立即提交，需要自行触发表单的提交。
             * @param {Function<JQuery.jqXHR>} onresult 指定一个回调，接收参数为jqXHR
             * @param {Function<FormData>} validFunc 表单验证函数，传入要验证的FormData，返回true表示验证成功，返回false表示验证失败，终止表单提交。
             * @param {Function<number,number>} upProgress 上传进度回调
             * @param {Function<number,number>} downProgress 下载进度回调
             */
            onSubmitForm: function (onresult: (result: WebApiResult) => void,
                validFunc?: (formData: FormData) => boolean,
                upProgress?: (loaded: number, total: number) => void,
                downProgress?: (loaded: number, total: number) => void) {
                var form = $(this);
                form.on("submit", function () {
                    var formData = new FormData(form[0]);
                    $("form").addClass('was-validated');
                    if (!(form[0].checkValidity()) || (validFunc && !validFunc(formData))) {
                        return false;//验证不成功
                    }
                    var apiresult = form.postForm(upProgress, downProgress);
                    if (onresult) {
                        onresult(apiresult);
                    }
                    return false; //阻止form使用浏览器内置提交功能

                });
            }

        });
    })(jQuery || $);

